perm filename CURVE.SAI[SYS,HE]1 blob sn#004194 filedate 1972-07-12 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00013 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00003 00002	ENTRY CURVE1
 00006 00003	⊃	DUMP INTERNAL ARRAYS FOR DEBUGGING
 00008 00004	⊃	COMPUTE LEAST SQUARES ERROR OF FIT AND RETURN
 00011 00005	⊃	MOVE POINTS NEAR CORNERS TO CLOSEST LINE
 00014 00006	⊃	MAKE A NEW LINE CONNECTING PARALLEL SEGMENTS
 00016 00007	⊃	HERE WE CURVE FIT ONE SEGMENT
 00018 00008		⊃	DISPLAY LINES FIT THROUGH ROW INDEX
 00020 00009		⊃	PASS 1, BREAK OUTLINE INTO SHORT SEGMENTS USING TOLER
 00024 00010		⊃	COMBINE SMALL SEGMENTS USING TOLER2
 00027 00011		⊃	COMPUTE NEW CORNERS AND DELETE EXTRA SEGMENTS
 00032 00012	⊃	STORE DATA IN OUTPUT ARRAY
 00034 00013	SIMPLE INTERNAL PROCEDURE CURVON
 00035 ENDMK
⊗;
ENTRY CURVE1;
BEGIN "CURVE"
REQUIRE "PREAMB.SAI[SYS,HE]" SOURCE_FILE;
REQUIRE "DPYSUB.HDR[SYS,HE]" SOURCE_FILE;
REQUIRE "MISCUR.REL" LOAD_MODULE;
REQUIRE "SQRT[SYS,HE]" LOAD_MODULE;
REQUIRE 500 STRING_SPACE;
REQUIRE "HELIB.REL[1,3]" LIBRARY;
REQUIRE -1 NEW_ITEMS;

INTERNAL REAL TOLER,MINLEN,TOLER2,CORDIF,CORMX;
INTERNAL BOOLEAN XDEB, DD_DISP, XDMP, DISCUR;
DEFINE SAFEX="SAFE",SMAX="60",⊃="COMMENT",CRLF="'15&'12";
REAL X,Y, XX, YY;
INTEGER DEND;
INTERNAL INTEGER FRAMEX;
EXTERNAL INTEGER FRAMEY;
SAFEX INTEGER ARRAY DISPL[1:300];

FORWARD PROCEDURE CUR2(REFERENCE INTEGER SCNT;SAFEX REAL ARRAY D,ODAT;INTEGER DSTR,S_MAX);
EXTERNAL PROCEDURE FADCHG(REAL X,Y; PROCEDURE PROC);
EXTERNAL PROCEDURE FRDCHG(REAL X,Y; PROCEDURE PROC);
EXTERNAL PROCEDURE DISP(REAL ARRAY D);
EXTERNAL REAL PROCEDURE SQRT(REAL X);

INTERNAL INTEGER PROCEDURE CUR1(SAFEX REAL ARRAY D,ODAT;REFERENCE INTEGER SCNT,S_MAX);
	BEGIN INTEGER STRT;
	TOLER←0.2;TOLER2←0.9;
	MINLEN←5.0;
	CORDIF ← 150.0; CORMX ← 1000.0;
	SCNT ← 0;
	STRT ← 1;
	DO	BEGIN
		CUR2(SCNT,D,ODAT,STRT,S_MAX);
		STRT ← D[STRT,2];
		END UNTIL ¬STRT;
	RETURN(IF SCNT<4 THEN -2 ELSE 0);
	END;

⊃	FIND A POINT ON LINE CLOSEST TO X,Y;

SIMPLE PROCEDURE GETPNT(REAL X,Y,A,B,C; REFERENCE REAL XX, YY);
	BEGIN
	IF ABS(A)>ABS(B) THEN
		BEGIN
		YY ← (-A*B*X+A↑2*Y+B*C)/(A↑2+B↑2);
		XX ← (C-B*Y)/A;
		END ELSE BEGIN
		XX ← (A*C+B↑2*X-A*B*Y)/(A↑2+B↑2);
		YY ← (C-A*X)/B;
		END;
	END;
⊃	DUMP INTERNAL ARRAYS FOR DEBUGGING;

SIMPLE PROCEDURE OUTDMP(STRING A; SAFEX REAL ARRAY D; INTEGER DEND);
	BEGIN INTEGER I,J;
	OUT(3,"FIT ARRAY DUMP - "&A&CRLF);
	FOR I ← 1 STEP 1 UNTIL DEND DO
		BEGIN
		SETFORMAT(2,0);
		OUT(3,CVS(I));
		SETFORMAT(11,2);
		FOR J←1 STEP 1 UNTIL 5 DO OUT(3,CVF(D[I,J]));
		SETFORMAT(8,2);
		FOR J←6 STEP 1 UNTIL 9 DO OUT(3,CVF(D[I,J]));
		SETFORMAT(7,1);
		FOR J←10 STEP 1 UNTIL 11 DO OUT(3,CVF(D[I,J]));
		OUT(3,CRLF);
		END;
	END;

⊃	DRAW AN ARROW_DPY;

SIMPLE INTERNAL PROCEDURE ARROW_DPY(REAL X,Y);
	BEGIN
	DPYBRT(3);
	FADCHG(X,Y,AIVECT);
	RVECT(60,0);
	RIVECT(-60,0);
	RVECT(20,14);
	RIVECT(0,-28);
	RVECT(-20,14);
	DPYBRT(7);
	END;

⊃	COMPUTE COEFICIENTS OF AX+BY=C;

EXTERNAL PROCEDURE COEF(SAFEX REAL ARRAY X);
⊃	COMPUTE LEAST SQUARES ERROR OF FIT AND RETURN;

EXTERNAL REAL PROCEDURE ERROR(SAFEX REAL ARRAY X);

⊃	CALCULATE NEW CORNER POSITION. TRUE IF CORNER
	EXISTS, FALSE IF LINES PARALLEL;

SIMPLE BOOLEAN PROCEDURE CORNER_CUR(SAFEX REAL ARRAY A1,A2;REFERENCE REAL X,Y);
	BEGIN REAL DENOM;
	IF ABS(DENOM←A1[7]*A2[8]-A1[8]*A2[7])<.001 THEN RETURN(FALSE);
	X ← (A2[8]*A1[9]-A1[8]*A2[9])/DENOM;
	Y ← (A1[7]*A2[9]-A2[7]*A1[9])/DENOM;
	RETURN(TRUE);
	END;

⊃	IN THE ROUTINES WHICH FOLLOW, SEVERAL ARRAYS ARE THE KEYS TO VICTORY

	D contains the raw edge points from the edge follower in the format
		described under the GET_DATA command.  Here, DSTR points to
		the start of the current block (the first coords in DSTR+1)
		and DEND points to the end of the block.  In between are the
		X,Y coordinate pairs.
	SUMS contains the output of pass 1, one seqment per row.  There are
		thirteen columns per row filled as follows:
		1-6 are the sums X, Y, X↑2, Y↑2, XY, and N
		7-9 are the line coefficients A, B, and C
		10-11 are pointers to the coords of the ends of the line
	SEGS is used in pass one to indicate breaks in the segment
		Each row points into D to the starting and ending
		coordinates of the  partial segment.
	INDEX is the last used row of SUMS
	SIND is the last used row of SEGS (and the one being processed)
	LOOP is TRUE is the initial segment was a closed curve
	ODAT is the output array containing the coordinates of the lines
	SCNT is the maximum index of ODAT
	TEMP, T1, and T2 hold rows of SUMS while being processed in later passes
	COUT holds the computed coordinates during pass 3
	;
⊃	MOVE POINTS NEAR CORNERS TO CLOSEST LINE;

PROCEDURE CORFIX(SAFEX REAL ARRAY F, L, D; INTEGER STR);
	BEGIN SAFEX REAL ARRAY T[1:11];
	BOOLEAN TOF;
	INTEGER P1, P2, INC, CNT;
	REAL E1, E2, X, Y, A, B, C;
	P1 ← F[11];
	X ← D[P1,1];
	Y ← D[P1,2];
	E1←ABS(((A←F[7])*X+(B←F[8])*Y-F[9])/SQRT(A↑2+B↑2));
	E2←ABS(((A←L[7])*X+(B←L[8])*Y-L[9])/SQRT(A↑2+B↑2));
	INC ← 1;
	IF ¬(TOF←E1<E2) THEN BEGIN ARRTRAN(T,F);ARRTRAN(F,L);ARRTRAN(L,T);INC ← -1;END;
	WHILE TRUE DO
		BEGIN
		L[1] ← L[1]-X;
		L[2] ← L[2]-Y;
		L[3] ← L[3]-X↑2;
		L[4] ← L[4]-Y↑2;
		L[5] ← L[5]-X*Y;
		L[6] ← L[6]-1.0;
		COEF(L);
		P1 ← P1+INC;
		IF P1>DEND THEN P1←STR+1 ELSE IF P1=STR THEN P1←DEND;
		IF ¬L[6] THEN DONE;
		X ← D[P1,1];
		Y ← D[P1,2];
		E1←ABS(((A←F[7])*X+(B←F[8])*Y-F[9])/SQRT(A↑2+B↑2));
		E2←ABS(((A←L[7])*X+(B←L[8])*Y-L[9])/SQRT(A↑2+B↑2));
		IF E1>E2 THEN DONE;
		IF E1<1.0 THEN
			BEGIN "ADDON"
			F[1] ← F[1]+X;
			F[2] ← F[2]+Y;
			F[3] ← F[3]+X↑2;
			F[4] ← F[4]+Y↑2;
			F[5] ← F[5]+X*Y;
			F[6] ← F[6]+1.0;
			COEF(F);
			END "ADDON";
		END;
	IF ¬TOF THEN BEGIN ARRTRAN(T,F);ARRTRAN(F,L);ARRTRAN(L,T);END;
	P2 ← P1-INC;
	IF P2>DEND THEN P2←STR+1 ELSE IF P2=STR THEN P2←DEND;
	F[11] ← IF TOF THEN P2 ELSE P1;
	L[10] ← IF TOF THEN P1 ELSE P2;
	IF F[6]≤1.0 THEN F[6] ←0.0;
	IF L[6]≤1.0 THEN L[6] ←0.0;
	RETURN;
	END;
⊃	MAKE A NEW LINE CONNECTING PARALLEL SEGMENTS;

BOOLEAN PROCEDURE MAKLIN(SAFEX REAL ARRAY A,B,C,D; INTEGER STR);
	BEGIN INTEGER P1, P2, P3, P4;
	REAL X, Y, XQ, YQ, XY, N;

	SIMPLE BOOLEAN PROCEDURE PROC(INTEGER P;REAL ARRAY Z,Q);
		BEGIN REAL AA, BB, E, XX, YY;
		XX ← Q[P,1];
		YY ← Q[P,2];
		E←ABS(((AA←Z[7])*XX+(BB←Z[8])*YY-Z[9])/SQRT(AA↑2+BB↑2));
		IF E<1.0 THEN RETURN(TRUE);
		X ← X+XX;
		Y ← Y+YY;
		XQ ← XQ+XX↑2;
		YQ ← YQ+YY↑2;
		XY ← XY+XX*YY;
		N ← N+1.0;
		Z[1] ← Z[1] -XX;
		Z[2] ← Z[2] -YY;
		Z[3] ← Z[3] -XX↑2;
		Z[4] ← Z[4] -YY↑2;
		Z[5] ← Z[5] -YY*XX;
		IF (Z[6]←Z[6]-1.0)≤0 THEN RETURN(TRUE);
		COEF(Z);
		RETURN(FALSE);
		END;

	X ← Y ← XQ ← YQ ← XY ← N ← 0;
	P1 ← A[11]; P2 ← B[10]; P3 ← A[10]; P4 ← B[11];
	DO	BEGIN "SUM1"
		IF PROC(P1,A,D) THEN DONE;
		IF (P1←P1-1)≤STR THEN P1←DEND;
		END "SUM1" UNTIL P1=P3;
	DO	BEGIN "SUM2"
		IF PROC(P2,B,D) THEN DONE;
		IF (P2←P2+1)>DEND THEN P2←STR+1;
		END "SUM2" UNTIL P2=P4;
	IF N<1.5 THEN RETURN(FALSE);
	C[1] ← X;
	C[2] ← Y;
	C[3] ← XQ;
	C[4] ← YQ;
	C[5] ← XY;
	C[6] ← N;
	COEF(C);
	A[11] ← P1;
	B[10] ← P2;
	C[10] ← IF (P1+1)>DEND THEN STR+1 ELSE P1+1;
	C[11] ← IF (P2-1)≤STR THEN DEND ELSE P2-1;
	RETURN(TRUE);
	END;
⊃	HERE WE CURVE FIT ONE SEGMENT;

PROCEDURE CUR2(REFERENCE INTEGER SCNT;SAFEX REAL ARRAY D, ODAT;INTEGER DSTR,S_MAX);
	BEGIN BOOLEAN LOOP, COMB, HALT;
	REAL EX, EY, E1, E2, EPS, LERR, AX, AY, X1, Y1;
	SAFEX REAL ARRAY SUMS[1:SMAX,1:11], TEMP,T1,T2,T3[1:11];
	SAFEX INTEGER ARRAY SEGS[1:SMAX,1:2];
	INTEGER INDEX, I, J, K, DPNT, SIND, PT1, PT2, L;
	LABEL L1, L2, L3, L4, L5, L6, L7, L8, L9, L10, L13;

	⊃	RETURN INDEX FOR COORDS FURTHEST FROM THE LINE THROUGH THE ENDPOINTS;

	INTEGER PROCEDURE GETMAX(INTEGER S,E);
		BEGIN REAL A,B,C,X1,X2,Y1,Y2,DENOM,M,T;
		EXTERNAL INTEGER PROCEDURE LOOP1(REAL ARRAY D;REAL A,B,C,DENOM;INTEGER I,DSTR,DEND,E);
		INTEGER I,J,K;
		X1 ← D[S,1];
		Y1 ← D[S,2];
		X2 ← D[E,1];
		Y2 ← D[E,2];
		A ← Y1-Y2;
		B ← X2-X1;
		C ← X1*Y2-X2*Y1;
		DENOM ← SQRT(A↑2+B↑2);
		I ← S-1;
		J ← LOOP1(D,A,B,C,DENOM,I,DSTR,DEND,E);
		IF ¬J THEN USERERR(0,0,"GETMAX LOST BIG"&CRLF);
		RETURN(J);
		END;
	⊃	DISPLAY LINES FIT THROUGH ROW INDEX;

	PROCEDURE DEBDIS(REAL TOLER,EPS; INTEGER INDEX, PAS);
		BEGIN INTEGER I, J, K;
		REAL X, Y, A, B, C;
		IF DD_DISP THEN
			BEGIN
			RELPOG(FRAMEX);
			IF PAS=1 THEN DISP(D);
			END;
		IF FRAMEX<0 THEN FRAMEX ← GETPOG;
		DPYSET(DISPL);
		DPYBRT(7);
		DPYBIG(3);
		FADCHG(10.0,240.0,AIVECT);
		SETFORMAT(0,0);
		DPYSST("PASS "&CVS(PAS));
		SETFORMAT(7,4);
		DPYSST("    TOLER="&CVF(TOLER)&"     EPS="&CVF(EPS));
		FADCHG(0,0,AIVECT);
		FOR I←1 STEP 1 UNTIL INDEX DO
			BEGIN
			J ← SUMS[I,10];
			K ← SUMS[I,11];
			A ← SUMS[I,7];
			B ← SUMS[I,8];
			C ← SUMS[I,9];
			GETPNT(D[J,1],D[J,2],A,B,C,X,Y);
			FRDCHG(X,Y,RIVECT);
			GETPNT(D[K,1],D[K,2],A,B,C,X,Y);
			FRDCHG(X,Y,RVECT);
			END;
		END;
	⊃	PASS 1, BREAK OUTLINE INTO SHORT SEGMENTS USING TOLER;

	IF DISCUR THEN
		BEGIN
		OUTSTR("DEBUG PASS 1?"&CRLF);
		XDEB ← INCHWL="Y";
		END;
	INDEX ← 0;
	DEND ← DSTR+(I←ABS(D[DSTR,1]));
	LOOP ← D[DSTR,1]>0;
	IF (LOOP∧I<6)∨(¬LOOP∧I<3) THEN GO TO L2;
	IF LOOP THEN
		BEGIN "LOOP"
		PT1 ← DSTR+1;
		PT2 ← (DSTR+DEND) DIV 2;
		SEGS[2,2] ← SEGS[1,1] ← GETMAX(PT1,PT2);
		SEGS[2,1] ← SEGS[1,2] ← GETMAX(PT2, PT1);
		SIND ← 2;
		END "LOOP" ELSE BEGIN "NO"
		SEGS[SIND←1,1] ← DSTR+1;
		SEGS[SIND,2] ← DEND;
		END "NO";
L1:	DO	BEGIN "MAIN"
		EXTERNAL PROCEDURE LOOP2(REAL ARRAY TEMP,D;INTEGER I,PT2,DEND,DSTR);
		PT1 ← SEGS[SIND,1];
		PT2 ← SEGS[SIND,2];
		I ← PT1-1;
		LOOP2(TEMP,D,I,PT2,DEND,DSTR);
		EPS ← ERROR(TEMP)/TEMP[6];
		IF XDEB THEN
			BEGIN "D1"
			DEBDIS(TOLER,EPS,INDEX,1);
			FOR J←SIND STEP -1 UNTIL 1 DO
				BEGIN REAL A,B,C,E;
				I ← SEGS[J,1];
				K ← SEGS[J,2];
				A ← D[I,1];
				B ← D[I,2];
				IF J=SIND∨A≠C∨B≠E THEN FRDCHG(A,B,RIVECT);
				C ← D[K,1];
				E ← D[K,2];
				FRDCHG(C,E,RVECT);
				END;
			ARROW_DPY(D[PT1,1], D[PT1,2]);
			ARROW_DPY(D[PT2,1], D[PT2,2]);
			DPYOUT(FRAMEX);
			INCHWL;
			END "D1";
		IF EPS>TOLER THEN
			BEGIN "BREAK"
			IF (SIND←SIND+1)>SMAX THEN USERERR(0,0,"SEGS OVERFLOWED"&CRLF);
			SEGS[SIND,1] ← PT1;
			SEGS[SIND-1,1]←SEGS[SIND,2]←GETMAX(PT1,PT2);
			GO TO L1;
			END "BREAK";
		IF (INDEX←INDEX+1)>SMAX THEN USERERR(0,0,"SUM ARRAY OVERFLOW"&CRLF);
		TEMP[10] ← PT1;
		TEMP[11] ← PT2;
L13:		IF INDEX>1 THEN
			BEGIN "SAVE"
			ARRBLT(T1[1],SUMS[INDEX-1,1],11);
			CORFIX(T1,TEMP,D,DSTR);
			IF T1[6] THEN ARRBLT(SUMS[INDEX-1,1],T1[1],11) ELSE INDEX←INDEX-1;
			END "SAVE";
		IF TEMP[6] THEN ARRBLT(SUMS[INDEX,1],TEMP[1],11) ELSE INDEX←INDEX-1;
		END "MAIN" UNTIL ¬(SIND ← SIND-1);
	IF INDEX>1∧LOOP THEN
		BEGIN "FINISH"
		ARRBLT(T1[1],SUMS[1,1],11);
		ARRBLT(T2[1],SUMS[INDEX,1],11);
		CORFIX(T2,T1,D,DSTR);
		I←INDEX;
		IF T1[6] THEN ARRBLT(SUMS[1,1],T1[1],11) ELSE
			BEGIN
			I←1;
			INDEX←INDEX-1;
			END;
		IF T2[6] THEN ARRBLT(SUMS[I,1],T2[1],11) ELSE INDEX←INDEX-1;
		END "FINISH";
	⊃	COMBINE SMALL SEGMENTS USING TOLER2;

L2:	IF DISCUR THEN
		BEGIN
		OUTSTR("DEBUG PASS 2?"&CRLF);
		XDEB←INCHWL="Y";
		RELPOG(FRAMEY);
		END;
L8:	COMB ← FALSE;
	I←1;
	IF INDEX≤1 THEN GO TO L10;
	HALT ← FALSE;
L5:	J ← I;
	ARRBLT(T1[1],SUMS[I,1],11);
L7:	IF J=1∧HALT THEN GO TO L3;
	IF (I←I+1)>INDEX THEN
		BEGIN HALT←TRUE;
		IF LOOP THEN I←1 ELSE GO TO L3;
		END;
	ARRBLT(T2[1],SUMS[I,1],11);
L6:	FOR K←1 STEP 1 UNTIL 6 DO TEMP[K]←T1[K]+T2[K];
	TEMP[10]←T1[10];
	TEMP[11]←T2[11];
	IF (I←I+1)>INDEX THEN
		BEGIN
		HALT ← TRUE;
		IF LOOP THEN I←1 ELSE GO TO L4;
		END;
	ARRBLT(T3[1],SUMS[I,1],11);
	FOR K←1 STEP 1 UNTIL 6 DO T1[K]←T2[K]+T3[K];
	T1[10] ← T2[10];
	T1[11]←T3[11];
L4:	E1 ← ERROR(TEMP)/TEMP[6];
	E2 ← ERROR(T1)/T1[6];
	IF XDEB THEN
		BEGIN
		DEBDIS(TOLER2,E1,INDEX,2);
		FADCHG(250.0,240.0,AIVECT);
		DPYSST("EPS2= "&CVF(E2));
		ARROW_DPY(D[TEMP[10],1],D[TEMP[10],2]);
		IF HALT∧¬LOOP THEN ARROW_DPY(D[TEMP[11],1],D[TEMP[11],2]) ELSE
			ARROW_DPY(D[T1[11],1],D[T1[11],2]);
		DPYOUT(FRAMEX);
		INCHWL;
		END;
	IF E1<TOLER2∧((HALT∧¬LOOP)∨E2>E1) THEN
		BEGIN
		IF ¬HALT∧LOOP∧J=1 THEN GO TO L9;
		COMB ← TRUE;
		IF J<INDEX THEN
			BEGIN
			ARRBLT(SUMS[J,1],TEMP[1],11);
			IF J+1<INDEX THEN ARRBLT(SUMS[J+1,1],SUMS[J+2,1],(INDEX-J-1)*11);
			END ELSE BEGIN
			ARRBLT(SUMS[1,1],TEMP[1],11);
			J ← 1;
			END;
		IF (INDEX ← INDEX-1)<I THEN I←1;
		IF HALT∧¬LOOP THEN GO TO L3;
		ARRTRAN(T1,TEMP);
		I ← J;
		GO TO L7;
		END;
	IF ¬HALT∨LOOP THEN IF E2<TOLER2 THEN
		BEGIN
		ARRTRAN(T1,T2);
		ARRTRAN(T2,T3);
		IF (J←J+1)>INDEX THEN J←1;
		GO TO L6;
		END ELSE BEGIN
L9:		ARRTRAN(T1,T3);
		J←I;
		IF ¬HALT∨J>2 THEN GO TO L7;
		END;
L3:	IF COMB THEN GO TO L8;
	⊃	COMPUTE NEW CORNERS AND DELETE EXTRA SEGMENTS;

L10:	IF DISCUR THEN
		BEGIN
		OUTSTR("DEBUG PASS 3?"&CRLF);
		XDEB ← INCHWL="Y";
		END;
	IF XDMP THEN OUTDMP("END OF PASS 2",SUMS,INDEX);
	IF INDEX<1∨(LOOP∧INDEX<3) THEN RETURN;
	FOR I←1 STEP 1 UNTIL INDEX DO
	   IF SUMS[I,6]<MINLEN ∧(LOOP∨(I≠1∧I≠INDEX)) THEN
		BEGIN "SHORT"
		ARRBLT(TEMP[1],SUMS[IF I-1>0 THEN I-1 ELSE INDEX,1],11);
		ARRBLT(T1[1],SUMS[IF I+1>INDEX THEN 1 ELSE I+1,1],11);
		J ← SUMS[I,10];
		K ← SUMS[I,11];
		AX ← (D[J,1]+D[K,1])/2;
		AY ← (D[J,2]+D[K,2])/2;
		IF CORNER_CUR(TEMP,T1,X,Y)∨(E1←((X-AX)↑2+(Y-AY)↑2)<CORDIF) THEN
			BEGIN "DELETE"
			ARRBLT(SUMS[I,1],SUMS[I+1,1],(INDEX-I)*11);
			INDEX ← INDEX-1;
			IF XDEB THEN
				BEGIN "D2"
				DEBDIS(CORDIF,E1,INDEX,3);
				FADCHG(250.0,240.0,AIVECT);
				DPYSST("DELETED");
				ARROW_DPY(X,Y);
				DPYOUT(FRAMEX);
				INCHWL;
				END "D2";
			END "DELETE";
		END "SHORT";
	IF INDEX<1∨(LOOP∧INDEX<3) THEN RETURN;
		BEGIN "COMPUT" SAFEX REAL ARRAY COUT[1:INDEX+10,1:2];
		LABEL L12, L9;
		L ← 1;
		IF ¬LOOP THEN
			BEGIN "NOLOP"
			GETPNT(D[SUMS[1,10],1],D[SUMS[1,10],2],SUMS[1,7],SUMS[1,8],SUMS[1,9],COUT[1,1],COUT[1,2]);
			L ← L+1;
			GETPNT(D[SUMS[INDEX,11],1],D[SUMS[INDEX,11],2],SUMS[INDEX,7],SUMS[INDEX,8],
				SUMS[INDEX,9],XX,YY);
			END "NOLOP";
		IF INDEX=1 THEN IF SUMS[1,6]<4 THEN RETURN ELSE GO TO L9;
		FOR I←1 STEP 1 UNTIL INDEX-1 DO
			BEGIN "CORNER"
			J←I+1;
	L12:		ARRBLT(T1[1],SUMS[I,1],11);
			ARRBLT(T2[1],SUMS[J,1],11);
			IF CORNER_CUR(T1,T2,X,Y) THEN
				BEGIN "FIND"
				PT1 ← T2[10];
				PT2 ← T1[11];
				EX ← D[PT1,1];
				EY ← D[PT1,2];
				AX ← D[PT2,1];
				AY ← D[PT2,2];
				E1←(EX-AX)↑2+(EY-AY)↑2;
				IF E1>CORDIF THEN OUTSTR("BAD CORNER MATCH"&CRLF);
				E2 ← IF E1<2.0 THEN (AX-X)↑2+(AY-Y)↑2
					ELSE (X-(AX+EX)/2)↑2+(Y-(AY+EY)/2)↑2;
				IF E2<CORDIF THEN
					BEGIN "GOOD"
					COUT[L,1] ← X;
					COUT[L,2] ← Y;
					END "GOOD" ELSE BEGIN "BAD"
					OUTSTR("BAD CORNER REJECTED"&CVF(E2)&'15&'12);
					IF E2>CORMX∧MAKLIN(T1,T2,TEMP,D,DSTR)∧
						CORNER_CUR(T1,TEMP,AX,AY)∧CORNER_CUR(TEMP,T2,EX,EY) THEN
						BEGIN "ADLINE"
						COUT[L,1] ← AX;
						COUT[L,2] ← AY;
						L ← L+1;
						COUT[L,1] ← EX;
						COUT[L,2] ← EY;
						END "ADLINE" ELSE BEGIN
						COUT[L,1] ← (EX+AX)/2;
						COUT[L,2] ← (EY+AY)/2;
						END;
					END "BAD";
				L ← L+1;
				END "FIND" ELSE BEGIN "NOF"
				FOR K←1 STEP 1 UNTIL 6 DO T1[K]←T1[K]+T2[K];
				T1[11] ← T2[11];
				COEF(T1);
				ARRBLT(SUMS[IF J=1 THEN J ELSE I,1],T1[1],11);
				ARRBLT(SUMS[I,1],SUMS[I+1,1],(INDEX-I)*11);
				INDEX ← INDEX-1;
				END "NOF";
			END "CORNER";
		IF INDEX=1 THEN GO TO L9;
		IF LOOP∧J>1 THEN
			BEGIN
			J←1;
			I←INDEX;
			GO TO L12;
			END;
		INDEX ← L-1;
L9:		IF INDEX<1∨(LOOP∧INDEX<3) THEN RETURN;
⊃	STORE DATA IN OUTPUT ARRAY;

		IF XDMP THEN OUTDMP("END OF PASS 3",SUMS,INDEX);
		IF SCNT+INDEX+1>S_MAX THEN OUTSTR("ODAT OVERFLOW"&CRLF) ELSE
			BEGIN
			ODAT[K←SCNT ← SCNT+1,1] ← IF LOOP THEN INDEX ELSE -INDEX-1;
			FOR I ← 1 STEP 1 UNTIL INDEX DO
				BEGIN
				SCNT ← SCNT+1;
				ODAT[SCNT,1] ← COUT[I,1];
				ODAT[SCNT,2] ← COUT[I,2];
				END;
			IF ¬LOOP THEN
				BEGIN
				SCNT ← SCNT+1;
				ODAT[SCNT,1]←XX;
				ODAT[SCNT,2]←YY;
				END;
			END;
		END "COMPUT";
	IF DISCUR THEN
		BEGIN
		RELPOG(FRAMEY);
		IF FRAMEX<0 THEN FRAMEX ← GETPOG;
		DPYSET(DISPL);
		DPYBRT(7);
		I ← 1;
		DO	BEGIN INTEGER L;
			J ← ABS(ODAT[I,1]);
			L ← I+J;
			FADCHG(ODAT[I+1,1],ODAT[I+1,2],AIVECT);
			FOR K←I+2 STEP 1 UNTIL L DO FRDCHG(ODAT[K,1],ODAT[K,2],RVECT);
			IF ODAT[I,1]>0 THEN FRDCHG(ODAT[I+1,1],ODAT[I+1,2],RVECT);
			I ← L+1;
			END UNTIL I≥SCNT;
		DPYOUT(FRAMEX);
		IF XDEB THEN
			BEGIN
			INCHWL;
			IF DD_DISP THEN RELPOG(FRAMEX) ELSE DISP(D);
			END;
		END;
	END;
SIMPLE INTERNAL PROCEDURE CURVON;
	BEGIN INTEGER I;
	OUTSTR("DISPLAY?");
	IF INCHWL="Y" THEN
		BEGIN
		DISCUR ← TRUE;
		IF ¬RUN THEN DPYTYP(-140,1,8);
		END ELSE BEGIN
		RELPOG(FRAMEX);
		RELPOG(FRAMEY);
		END;
	OUTSTR("DUMP?");
	IF INCHWL="Y" THEN
		BEGIN
		OPEN(3,"DSK",0,0,2,100,I,I);
		ENTER(3,"CURVE.DBG",I);
		XDMP ← TRUE;
		END;
	END;

SIMPLE INTERNAL PROCEDURE CUROFF;
	BEGIN
	DISCUR ← XDMP ← XDEB ← FALSE;
	HYDPOG(FRAMEX);
	HYDPOG(FRAMEY);
	RELEASE(3);
	END;

END;